package com.css.fxfzcpxx.modules.util;

import com.alibaba.fastjson.util.IOUtils;

import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import com.css.fxfzcpxx.base.attachment.entity.AttachmentInfoEntity;
import com.css.fxfzcpxx.base.attachment.service.AttachmentInfoService;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.UUID;

/**
 * @Author: zhangSongRui
 * @CreateTime: 2023/04/28
 * @Description: word转pdf
 */
@RestController
@Slf4j
@RequestMapping("/pdf")
public class PDFController {
    @Autowired
    private AttachmentInfoService attachmentInfoService;
    @Value("${image.localDir}")
    private String localDir;

    public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };

    /**
     * 使用HWPFDocument解析word文档
     * wps按doc处理即可
     *
     * @param attachId   文件id
     */
    @GetMapping("/getPDF")
    @Operation(summary = "word转pdf")
    public void parseDocByHWPFDocument(String attachId) {

        AttachmentInfoEntity attach = attachmentInfoService.getAttach(attachId);
        String path = localDir  + attach.getAttachPath();
        String attachName = attach.getAttachName();
        String[] split = attachName.split("\\.");
        if (path.endsWith("pdf")){
            byPDF(attach);
            return;
        }
        boolean execute = false;
        File tempFile = null;
        File wordFile = null;
        File pdfFile = null;
        IConverter converter = null;
        FileInputStream is = null;
        FileInputStream io = null;
        OutputStream os = null;
        FileOutputStream out = null;
        try {
            // docx文件转换为doc
            if (path.endsWith("docx")) {
                FileInputStream inputStream = new FileInputStream(new File(path));
                // 临时输出路径
                tempFile = new File(localDir + UUID.randomUUID().toString() + ".doc");
                FileOutputStream outputStream = new FileOutputStream(tempFile);
                converter = LocalConverter.builder().build();
                // docx 转 doc. 成功返回true
                execute = converter.convert(inputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.DOC).execute();
                is = new FileInputStream(tempFile);
            } else {
                //如果不是docx直接转pdf
                FileInputStream inputStream = new FileInputStream(new File(path));
                // 临时输出路径
                tempFile = new File(localDir + UUID.randomUUID().toString() + ".doc");
                FileOutputStream outputStream = new FileOutputStream(tempFile);
                converter = LocalConverter.builder().build();
                // doc 转 doc. 成功返回true  如果不转则在进行doc处理时无效
                execute = converter.convert(inputStream).as(DocumentType.DOC).to(outputStream).as(DocumentType.DOC).execute();
                is = new FileInputStream(new File(path));
            }
            if (execute) {
                //对doc进行处理
                HWPFDocument document = new HWPFDocument(is);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();// 字节流，用来存储图片
                // When POI 3.18 is out, replace this with PictureRunMapper  3.18之后用PictureRunMapper ,之前用PicturesSource;
                PictureRunMapper pictures = new PictureRunMapper(document);
//                PicturesSource pictures = new PicturesSource(document);
                PicturesTable pictureTable = document.getPicturesTable();
                Range r = document.getRange();// 区间
                for (int i = 0; i < r.numParagraphs(); i++) {
                    Paragraph p = r.getParagraph(i);// 段落
                    // 以下代码解析图片,这样获取的图片是在文档流中的，是和文本按顺序解析的，可以很好的解决图片定位问题
                    for (int j = 0; j < p.numCharacterRuns(); j++) {
                        CharacterRun cr = p.getCharacterRun(j);// 字符
                        if (pictureTable.hasPicture(cr)) {
                            Picture picture = pictures.getFor(cr);
                            // 如果是在页面显示图片，可转换为base64编码的图片
                            picture.writeImageContent(baos);// 将图片写入字节流
                        }
                    }
                }
                // 将处理过的doc写到另一个word文件中
                wordFile = new File(localDir+UUID.randomUUID().toString()+".doc");
                out = new FileOutputStream(wordFile, false);
                // 把doc输出到输出流中
                document.write(out);
                // 将生成的word转换为pdf
                // 读取的word输入流
                FileInputStream inputStreamWord = new FileInputStream(wordFile);
                pdfFile = new File(localDir+split[0]+".pdf");
                FileOutputStream outputStreamPdf = new FileOutputStream(pdfFile);
                execute = converter.convert(inputStreamWord).as(DocumentType.DOC).to(outputStreamPdf).as(DocumentType.PDF).execute();
                if (execute) {
                    converter.shutDown();
                }
                io = new FileInputStream(pdfFile);

            }
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert requestAttributes != null;
            HttpServletResponse response = requestAttributes.getResponse();
            assert response != null;
            response.reset();
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(split[0]+".pdf","UTF-8") + "\"");
            // 跨域
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Method", "POST,GET");
            // PrintWrite pw=response.getWriter();  或
            os = response.getOutputStream();
            int flag = 0;
            while ((flag = io.read()) != -1) {
                os.write(flag);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        } finally {
            try {
                if(io != null){
                    io.close();
                }
                if(os != null){
                    os.flush();
                    os.close();
                }
                if(is != null) {
                    is.close();
                }
                if(out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 删除转换后的临时文件地址
            tempFile.delete();
            //删除保存处理好的doc的临时文件
            wordFile.delete();
            // 删除临时pdf文件
            pdfFile.delete();

        }
    }


    public void byPDF( AttachmentInfoEntity attachmentInfoEntity) {
        OutputStream os = null;
        InputStream is = null;
        try{
            String attachPath = attachmentInfoEntity.getAttachPath();
            if (org.apache.commons.lang3.StringUtils.isNotBlank(attachPath)) {
                // 防乱码
//                    String name =
//                        new String(realFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                assert requestAttributes != null;
                HttpServletResponse response = requestAttributes.getResponse();
                assert response != null;
                response.reset();
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(attachmentInfoEntity.getAttachName(),"UTF-8") + "\"");
                // 跨域
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Method", "POST,GET");
                String name = localDir  + attachPath;
                is = new FileInputStream(new File(name));

                // PrintWrite pw=response.getWriter();  或
                os = response.getOutputStream();
                int flag = 0;
                while ((flag = is.read()) != -1) {
                    os.write(flag);
                }
            }
        } catch (Exception e){
            e.printStackTrace();
            System.out.println(e.getMessage());
        } finally{
            try{
                if(is != null){
                    is.close();
                }
                if(os != null){
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    @GetMapping("/exportPreview/{attachId}")
    public void exportPreview(@PathVariable("attachId") String attachId, HttpServletResponse response) throws Exception {

            AttachmentInfoEntity attach = attachmentInfoService.getAttach(attachId);
            String path = localDir  + attach.getAttachPath();
            String attachName = attach.getAttachName();
            String[] split = attachName.split("\\.");
            if (path.endsWith("pdf")){
                byPDF(attach);
                return;
            }

            FileInputStream fileInputStream = new FileInputStream(new File(path));

            XWPFDocument document = new XWPFDocument(fileInputStream);

            // 定义word文件名称、路径
            String docFilePath=localDir+File.separator+attachId+".doc"; //按照自己实际下载路径
            // 定义PDF文件名称、路径
            String pdfFilePath=localDir+File.separator+attachId+split[0]+".pdf";
            // 文档对象内容写入word
            saveFile(document, docFilePath);
            // word转PDF
            //doc2pdf(docFilePath, pdfFilePath);
            docxToPdf(docFilePath, pdfFilePath);

            response.setContentType("application/pdf");
            // 返回PDF
            writeBytes(pdfFilePath, response.getOutputStream());
    }



    /**保存word*/
    public  static void saveFile(XWPFDocument doc,String filePath){
        FileOutputStream fileOutputStream=null;
        try{
            fileOutputStream =new FileOutputStream(filePath);
            ByteArrayOutputStream bao=new ByteArrayOutputStream();
            doc.write(bao);
            fileOutputStream.write(bao.toByteArray());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static boolean getLicense() {
        boolean result = false;
        try {
            InputStream is = PDFController.class.getClassLoader().getResourceAsStream("license.xml"); //  license.xml应放在..\WebRoot\WEB-INF\classes路径下

            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public static String docxToPdf(String filePath, String pdfDir) {
        //getLicense();
        String pdfPath = pdfDir;
        try {
            // 加载Word文档
            Document doc = new Document(String.valueOf(Paths.get(filePath).toUri().toURL()));
            // 将文档保存为PDF格式
            doc.save(pdfPath, SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pdfPath;
    }

    public static void writeBytes(String filePath, OutputStream os) throws IOException
    {
        FileInputStream fis = null;
        try
        {
            File file = new File(filePath);
            if (!file.exists())
            {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) > 0)
            {
                os.write(b, 0, length);
            }
        }
        catch (IOException e)
        {
            throw e;
        }
        finally
        {
            IOUtils.close(os);
            IOUtils.close(fis);
        }
    }
}
